import gdata.spreadsheet.service
import gdata.docs.data
import gdata.docs.client
from itertools import *

class GoogleSpreadsheet:

  def __init__(self, username, password):
    self.username = username
    self.password = password
    self.connect()

  def connect(self, retry=3):
    for i in range(retry):
      try:
        self.client = gdata.spreadsheet.service.SpreadsheetsService()
        self.client.source = "UOIT Pages"
        self.client.email = self.username
        self.client.password = self.password
        self.client.ProgrammaticLogin()
      except Exception, e:
        if i == retry-1:
          raise(e)
      else:
        break
    for i in range(retry):
      try:
        self.client2 = gdata.docs.client.DocsClient()
        self.client2.ssl = True
        self.client2.ClientLogin(self.username, self.password, self.client.source)
      except Exception, e:
        if i == retry-1:
          raise(e)
      else:
        break
    return self

  def folders(self):
    feed = self.client2.GetDocList(uri="/feeds/default/private/full/-/folder")
    F = dict()
    for f in feed.entry:
      F[f.title.text] = dict(
        key = f.id.text.split("/")[-1].split("%3A")[-1],
        uri = f.content.src)
    return F

  def listfolder(self, uri=None, key=None, title=None):
    if title:
      uri = self.folders()[title]['uri']

    if key:
      uri = 'https://docs.google.com/feeds/default/private/' + \
            'full/folder%%3A%s/contents' % key
    feed = self.client2.GetDocList(uri=uri)
    F = dict()
    updated = []
    for x in feed.entry:
      F[x.title.text] = dict(
        key = x.id.text.split("/")[-1].split("%3A")[-1],
        uri = x.content.src,
        updated = x.updated.text)
      updated.append(x.updated.text)
    F['updated'] = max(updated)
    return F

  def listsheet(self, key):
    feed = self.client.GetWorksheetsFeed(key)
    ws = dict()
    for x in feed.entry:
      ws[x.title.text] = dict(
        key=x.id.text.split("/")[-1],
        updated=x.updated.text)
    return ws

  def data(self, skey, wkey):
    feed = self.client.GetListFeed(skey, wkey)
    for cell in feed.entry:
      yield dict((x, cell.custom[x].text) for x in cell.custom.keys())

  def mapdata(self, skey, wkey):
    return dict(
      (x['property'].lower().replace(' ', ''),
       x['value'] if x['value'] else "") for x in self.data(skey, wkey))

class Bundle(dict):
  def __init__(self, *E, **F):
    dict.__init__(self, *E, **F)
  def __getattr__(self, attr):
    if attr in self.__dict__:
      return getattr(self, attr)
    else:
      return self.get(attr)
  def __setattr__(self, k, v):
    self[k] = v

def flatten(data):
  """ flattens a data sheet into a sequence of records:
    data: dict(key1=>list(record))
    returns: list(dict(record, type=key1))
  """
  for (x, list1) in data.items():
    for r in list1:
      yield Bundle(r, type=x)

def alias(recordfeed, **F):
  """ Rename attribute names according to the rename map """
  for record in recordfeed:
    yield Bundle((F.get(k,k), v) for (k,v) in record.items())

def project(recordfeed, transform):
  """ Generalized projection: transform is dict(attr=>T)
      where T can be None: keep the attribute,
               attr-name : record[attr-name]
           lambda r: f(r): evaluate the function """
  def T(k, t, record):
    if t == None:
      return record[k]
    elif isinstance(t, str):
      return record[t]
    else:
      return t(record)

  for record in recordfeed:
    yield dict(
      (k, T(k, t, record)) for k, t in transform.items())

